/*
 * BlocksNumCache.cpp
 *
 *  Created on: Jun 11, 2010
 *      Author: Lukasz Spintzyk
 */

#include "ph.h"
#include "BlocksNumCache.h"
#include "Inode.h"
#include "InodeReader.h"
#include "BlockReader.h"
#include "SuperBlock.h"

BlocksNumCache::BlocksNumCache(
	InodePtr fileInode,
	InodeManager& inodeMgr,
	BlockManager& blockMgr)
	:d_fileInode(fileInode)
	,d_inodeMgr(inodeMgr)
	,d_blockMgr(blockMgr)
	,d_blocksCache(new uint32_t[d_inodeMgr.getSuperBlock().d_blockSize/sizeof(uint32_t)])
	,d_startCache(0)
	,d_endCache(0)
{
}

BlocksNumCache::~BlocksNumCache()
{
	delete[] d_blocksCache;
}

BlocksNumCache::BlocksNumCache(const BlocksNumCache& cache)
	:d_fileInode(cache.d_fileInode)
	,d_inodeMgr(cache.d_inodeMgr)
	,d_blockMgr(cache.d_blockMgr)
	,d_blocksCache(new uint32_t[d_inodeMgr.getSuperBlock().d_blockSize/sizeof(uint32_t)])
	,d_startCache(cache.d_startCache)
	,d_endCache(cache.d_endCache)
{
	memcpy(d_blocksCache, cache.d_blocksCache, d_inodeMgr.getSuperBlock().d_blockSize);
}


void BlocksNumCache::updateBlocksCacheIfNeeded(uint32_t block_num)
{
	if (blockNumNotCached(block_num))
	{
		updateCache(block_num);
	}
}

/*****************************************************************************/
/*****************************************************************************/

bool BlocksNumCache::blockNumNotCached(uint32_t blockNum)
{
	if (d_startCache == d_endCache) return true;

	if (d_startCache > blockNum) return true;

	if ((d_startCache < blockNum) &&
		(d_endCache <= blockNum)) return true;


	return false;
}

/*****************************************************************************/
/*****************************************************************************/

uint32_t BlocksNumCache::rewindEndCache(uint32_t rel_pos)
{
	uint32_t max = d_inodeMgr.getSuperBlock().d_blockSize/sizeof(uint32_t);

	for (d_endCache = rel_pos; d_endCache < max; ++d_endCache)
	{
		if (d_blocksCache[d_endCache] == 0)
		{
			break;
		}
	}

	if (d_blocksCache[d_endCache])
	{
		assert(d_endCache == max);
		d_endCache++;
	}
	d_endCache = d_startCache + d_endCache;
	return d_endCache;

}

void BlocksNumCache::updateCache(uint32_t block_index)
{
	if (block_index > DIRECT_LAST_INDEX)
	{
		uint32_t rel_pos = d_inodeMgr.getBlkNumRange(d_fileInode, block_index, d_blocksCache);
		d_startCache = block_index - rel_pos;
		//assert(d_blocksCache[rel_pos] > 0);
		d_endCache = rewindEndCache(rel_pos);
		//d_endCache = d_startCache + d_inodeMgr.getSuperBlock().d_blockSize/sizeof(uint32_t);
	}
	else
	{
		d_startCache = 0;
		d_endCache = DIRECT_LAST_INDEX+1;
		memcpy(d_blocksCache, &d_fileInode->d_block, (DIRECT_LAST_INDEX+1)*sizeof(uint32_t));
	}
}

/*****************************************************************************/
/*****************************************************************************/

uint32_t BlocksNumCache::cachedBlkIndex2Num(uint32_t block_index)
{
	updateBlocksCacheIfNeeded(block_index);
	assert(block_index - d_startCache>=0);
	//assert(d_blocksCache[block_index - d_startCache] > 0);
	return d_blocksCache[block_index - d_startCache];
}
